#include <QtSerialPort>
#include <QMessageBox>
#include <QFileDialog>
#include <QByteArray>
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "util.h"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , tcpClient(new TCPClient(this))
    , serialComm(new SerialComm(this))
    , fsu(nullptr)
    , action(NEXT_STEP_ACTION_WRITE)
{
    ui->setupUi(this);

    setWindowIcon(QIcon(":/new/status/icon/tool.png"));
    setWindowTitle("驱动调测工具");

    setWindowFlags(windowFlags() &~ Qt::WindowMaximizeButtonHint);
    setFixedSize(this->width(),this->height());

    ui->disconnectBtn->setEnabled(false);
    ui->closeCommBtn->setEnabled(false);
    ui->driverUnloadBtn->setEnabled(false);
    ui->controllerBtn->setEnabled(false);

    ui->aiTable->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Fixed);
    ui->aiTable->setColumnWidth(0, 50);
    ui->aiTable->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Fixed);
    ui->aiTable->setColumnWidth(1, 50);
    ui->aiTable->horizontalHeader()->setSectionResizeMode(2,QHeaderView::Fixed);
    ui->aiTable->setColumnWidth(2, 50);

    ui->diTable->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Fixed);
    ui->diTable->setColumnWidth(0, 50);
    ui->diTable->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Fixed);
    ui->diTable->setColumnWidth(1, 50);
    ui->diTable->horizontalHeader()->setSectionResizeMode(2,QHeaderView::Fixed);
    ui->diTable->setColumnWidth(2, 50);

    ui->siTable->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Fixed);
    ui->siTable->setColumnWidth(0, 50);
    ui->siTable->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Fixed);
    ui->siTable->setColumnWidth(1, 50);
    ui->siTable->horizontalHeader()->setSectionResizeMode(2,QHeaderView::Fixed);
    ui->siTable->setColumnWidth(2, 50);

    QList<QSerialPortInfo> portList = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &portInfo : portList)
    {
        ui->commComboBox->addItem(portInfo.portName());
    }

    ui->parityComboBox->addItem("无校验",QVariant(0));
    ui->parityComboBox->addItem("偶校验",QVariant(2));
    ui->parityComboBox->addItem("奇校验",QVariant(3));

    QObject::connect(tcpClient,&TCPClient::opened,this,&MainWindow::opened);
    QObject::connect(tcpClient,&TCPClient::closed,this,&MainWindow::closed);
    QObject::connect(tcpClient,&TCPClient::received,this,&MainWindow::readed);

    QObject::connect(serialComm,&SerialComm::opened,this,&MainWindow::opened);
    QObject::connect(serialComm,&SerialComm::closed,this,&MainWindow::closed);
    QObject::connect(serialComm,&SerialComm::received,this,&MainWindow::readed);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_connectButton_clicked()
{
    fsu = tcpClient;
    QString ip = ui->ipEdit->text();
    QString port = ui->portEdit->text();
    QString host = ip+":"+port;
    tcpClient->open(host);
}

void MainWindow::on_disconnectBtn_clicked()
{
    tcpClient->close();
}

void MainWindow::on_openCommBtn_clicked()
{
    fsu = serialComm;
    if(ui->commComboBox->currentIndex()==0){
        QMessageBox::warning(this, "提示", "请选择一个串口");
        return;
    }
    if(ui->baudComboBox->currentIndex()==0){
        QMessageBox::warning(this, "提示", "请选择串口波特率");
        return;
    }
    if(ui->parityComboBox->currentIndex()==0){
        QMessageBox::warning(this, "提示", "请选择校验");
        return;
    }
    QString commName = ui->commComboBox->currentText();
    QString baud = ui->baudComboBox->currentText();
    int parity = ui->parityComboBox->itemData(ui->parityComboBox->currentIndex()).toInt();
    QString dataBit = ui->dataBitEdit->text();
    QString stopBit = ui->stopBitEdit->text();

    QString parameter = QString("%1:%2:%3:%4:%5").arg(commName).arg(baud).arg(dataBit).arg(parity).arg(stopBit);
    serialComm->open(parameter);

}


void MainWindow::on_closeCommBtn_clicked()
{
    serialComm->close();
}

void MainWindow::opened()
{
    if (dynamic_cast<TCPClient*>(fsu))
    {
        ui->tcpConnectStatus->setIcon(QIcon(":/new/status/icon/green.png"));
        ui->disconnectBtn->setEnabled(true);
        ui->connectButton->setEnabled(false);
        ui->openCommBtn->setEnabled(false);
    }else{
        ui->commStatus->setIcon(QIcon(":/new/status/icon/green.png"));
        ui->closeCommBtn->setEnabled(true);
        ui->openCommBtn->setEnabled(false);
        ui->connectButton->setEnabled(false);
    }

}

void MainWindow::closed()
{
    if (dynamic_cast<TCPClient*>(fsu))
    {
        ui->tcpConnectStatus->setIcon(QIcon(":/new/status/icon/red.png"));
        ui->disconnectBtn->setEnabled(false);
        ui->connectButton->setEnabled(true);
        ui->openCommBtn->setEnabled(true);

    }else{
        ui->commStatus->setIcon(QIcon(":/new/status/icon/red.png"));
        ui->closeCommBtn->setEnabled(false);
        ui->openCommBtn->setEnabled(true);
        ui->connectButton->setEnabled(true);
    }
}

void MainWindow::readed(const QByteArray &data)
{
    qDebug()<<"rece:"<<Util::toHexadecimal(data);
    if(MAX_RESPONES_BUFFER_SIZE-p_driver_context->response_data_length>=data.length())
        memcpy(p_driver_context->response_data_buffer+p_driver_context->response_data_length,data.data(),data.length());
    else
        p_driver_context->response_data_length = 0;

}

void MainWindow::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == timerId)
    {
        if(action==NEXT_STEP_ACTION_WRITE){
            driverDll.fn_request(p_driver_context);
            if(p_driver_context->request_data_length>0){
                fsu->write(QByteArray(reinterpret_cast<char *>(p_driver_context->request_data_buffer),p_driver_context->request_data_length));
            }
            action = NEXT_STEP_ACTION_READ;
        }else if(action==NEXT_STEP_ACTION_READ){
            response_data_analysis_result result;
            driverDll.fn_response(p_driver_context,&result);
            switch(result.analysis_result)
            {
            case RESPONSE_DATA_ANALYSIS_SUCCESS:
                updateChannelValue(&result);
                action = NEXT_STEP_ACTION_WRITE;
                break;
            case RESPONSE_DATA_CONTINUE_READ:
                action = NEXT_STEP_ACTION_READ;
                break;
            case RESPONSE_DATA_DISCARD_ALL:
                action = NEXT_STEP_ACTION_WRITE;
                break;
            case RESPONSE_DATA_DISCARD_PART:
                action = NEXT_STEP_ACTION_READ;
                break;
            case RESPONSE_DATA_VALIDATION_ERROR:
                action = NEXT_STEP_ACTION_WRITE;
                break;
            default:
                action = NEXT_STEP_ACTION_WRITE;
                break;
            }
        }
    } else
    {
        QObject::timerEvent(event);
    }
}

void MainWindow::updateChannelValue(response_data_analysis_result *presult)
{
    for(int i=0;i<presult->channel_count;++i){
        if (presult->channel_value[i].value_type == 1){
            updateTableWidget(ui->aiTable,&presult->channel_value[i],QString::number(presult->channel_value[i].analog_value));
        }
        if (presult->channel_value[i].value_type == 2){
            updateTableWidget(ui->diTable,&presult->channel_value[i],QString::number(presult->channel_value[i].digital_value));
        }
        if (presult->channel_value[i].value_type == 3){
            updateTableWidget(ui->siTable,&presult->channel_value[i],QString::fromUtf8(reinterpret_cast<const char*>(presult->channel_value[i].string_value),
                                                                                         presult->channel_value[i].string_len));
        }
    }
}

void MainWindow::updateTableWidget(QTableWidget * table,driver_channel_value *pvalue,QString value)
{
    bool finded = false;
    int rowCount = table->rowCount();
    for (int row = 0; row < rowCount; ++row) {
        int x = table->item(row, 0)->text().toInt();
        int y = table->item(row, 1)->text().toInt();
        int z = table->item(row, 2)->text().toInt();
        if(x==pvalue->x && y==pvalue->y && z==pvalue->z){
            QTableWidgetItem *tableItem3 = new QTableWidgetItem(value);
            tableItem3->setTextAlignment(Qt::AlignCenter);
            table->setItem(row, 3, tableItem3);
            finded = true;
            break;
        }
    }
    if(!finded){
        int rowCount = table->rowCount();
        table->insertRow(rowCount);
        QTableWidgetItem *tableItem0 = new QTableWidgetItem(QString::number(pvalue->x));
        QTableWidgetItem *tableItem1 = new QTableWidgetItem(QString::number(pvalue->y));
        QTableWidgetItem *tableItem2 = new QTableWidgetItem(QString::number(pvalue->z));
        QTableWidgetItem *tableItem3 = new QTableWidgetItem(value);
        tableItem0->setTextAlignment(Qt::AlignCenter);
        tableItem1->setTextAlignment(Qt::AlignCenter);
        tableItem2->setTextAlignment(Qt::AlignCenter);
        tableItem3->setTextAlignment(Qt::AlignCenter);

        table->setItem(rowCount, 0, tableItem0);
        table->setItem(rowCount, 1, tableItem1);
        table->setItem(rowCount, 2, tableItem2);
        table->setItem(rowCount, 3, tableItem3);
    }
}


void MainWindow::on_driverSelectBtn_clicked()
{
    dllFileName = QFileDialog::getOpenFileName(nullptr, "选择驱动文件", "", "所有文件 (*.*)");
    ui->driverPathLineEdit->setText(dllFileName);
}


void MainWindow::on_driverLoadBtn_clicked()
{
    if( !driverDll.load(dllFileName) )
    {
        ui->driverLoadBtn->setEnabled(true);
        ui->driverUnloadBtn->setEnabled(false);
        ui->controllerBtn->setEnabled(false);
        QMessageBox::warning(this, "提示", "驱动动态库加载失败");
    }else{
        ui->driverLoadBtn->setEnabled(false);
        ui->driverUnloadBtn->setEnabled(true);
        ui->controllerBtn->setEnabled(true);

        QString parameter = ui->driverParameterEdit->toPlainText();
        if(parameter.isEmpty()){
            p_driver_context = driverDll.fn_new_driver(nullptr);
        }else{
            QByteArray byteArray = parameter.toUtf8();
            const unsigned char* data = reinterpret_cast<const unsigned char*>(byteArray.constData());
            p_driver_context = driverDll.fn_new_driver(const_cast<unsigned char *>(data));
        }
        timerId = startTimer(5000);
    }
}

void MainWindow::on_driverUnloadBtn_clicked()
{
    killTimer(timerId);
    ui->driverLoadBtn->setEnabled(true);
    ui->driverUnloadBtn->setEnabled(false);
    ui->controllerBtn->setEnabled(false);
}


void MainWindow::on_controllerBtn_clicked()
{

}

